All files / src/app/(site)/support/tickets/[id] TicketDetailWrapper.tsx

0% Statements 0/101
100% Branches 0/0
0% Functions 0/1
0% Lines 0/101

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                                                                                                                                                                                           
'use client';

/**
 * TicketDetailWrapper - Client component that fetches ticket and manages state
 */

import React, { useState, useEffect, useCallback } from 'react';
import { SupportTicketWithRelations } from '@/types/support';
import TicketDetail from '@/components/features/support/SupportPortal/TicketDetail';

interface TicketDetailWrapperProps {
  ticketId: string;
}

export default function TicketDetailWrapper({ ticketId }: TicketDetailWrapperProps) {
  const [ticket, setTicket] = useState<SupportTicketWithRelations | null>(null);
  const [loading, setLoading] = useState(true);
  const [actionLoading, setActionLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchTicket = useCallback(async () => {
    try {
      const response = await fetch(`/api/support/tickets/${ticketId}`);
      if (!response.ok) throw new Error('Failed to fetch ticket');
      const data = await response.json();
      setTicket(data.ticket);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'An error occurred');
    } finally {
      setLoading(false);
    }
  }, [ticketId]);

  useEffect(() => {
    fetchTicket();
  }, [fetchTicket]);

  const handleSendMessage = async (content: string) => {
    setActionLoading(true);
    try {
      const response = await fetch(`/api/support/tickets/${ticketId}/messages`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ content })});

      if (!response.ok) throw new Error('Failed to send message');

      await fetchTicket();
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to send message');
    } finally {
      setActionLoading(false);
    }
  };

  const handleCloseTicket = async () => {
    setActionLoading(true);
    try {
      const response = await fetch(`/api/support/tickets/${ticketId}/close`, {
        method: 'POST'});

      if (!response.ok) throw new Error('Failed to close ticket');

      await fetchTicket();
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to close ticket');
    } finally {
      setActionLoading(false);
    }
  };

  if (loading) {
    return (
      <div className="max-w-4xl mx-auto px-4 py-8">
        <div className="animate-spin h-8 w-8 border-4 border-blue-600 border-t-transparent rounded-full mx-auto" />
      </div>
    );
  }

  if (error || !ticket) {
    return (
      <div className="max-w-4xl mx-auto px-4 py-8">
        <div className="bg-red-50 text-red-700 px-4 py-3 rounded-lg">
          {error || 'Ticket not found'}
        </div>
      </div>
    );
  }

  const showSurvey = ticket.status === 'RESOLVED' && !ticket.survey;

  return (
    <TicketDetail
      ticket={ticket}
      onSendMessage={handleSendMessage}
      onCloseTicket={handleCloseTicket}
      isLoading={actionLoading}
      showSurvey={showSurvey}
    />
  );
}